# -*- coding: utf-8 -*-
"""
工具类和辅助函数

功能说明:
- 提供通用的工具函数
- API响应格式化
- 请求数据验证
- 时间处理和格式化
- 数据转换和处理

作者: MetasoCreator Team
创建时间: 2025-08-19
"""

from flask import jsonify
from typing import Dict, Any, List, Optional, Union
from datetime import datetime, timezone
import re
import json
import hashlib
import uuid



def create_api_response(
    success: bool = True,
    data: Optional[Dict[str, Any]] = None,
    message: str = "",
    status_code: int = 200,
    **kwargs
) -> tuple:
    """
    创建标准化的API响应格式
    
    Args:
        success: 操作是否成功
        data: 响应数据
        message: 响应消息
        status_code: HTTP状态码
        **kwargs: 其他额外字段
    
    Returns:
        tuple: (响应JSON, 状态码)
    """
    response = {
        'success': success,
        'timestamp': datetime.now(timezone.utc).isoformat(),
        'message': message
    }
    
    if data is not None:
        response['data'] = data
    
    # 添加额外字段
    for key, value in kwargs.items():
        if key not in response:
            response[key] = value
    
    return jsonify(response), status_code


def validate_request_data(data: Dict[str, Any], required_fields: List[str]) -> tuple:
    """
    验证请求数据是否包含必需字段
    
    Args:
        data: 请求数据字典
        required_fields: 必需字段列表
    
    Returns:
        tuple: (是否有效, 错误消息)
    """
    if not data:
        return False, "请求数据不能为空"
    
    missing_fields = []
    for field in required_fields:
        if field not in data or data[field] is None:
            missing_fields.append(field)
        elif isinstance(data[field], str) and not data[field].strip():
            missing_fields.append(field)
    
    if missing_fields:
        return False, f"缺少必需字段: {', '.join(missing_fields)}"
    
    return True, ""


def validate_email(email: str) -> bool:
    """
    验证邮箱格式
    
    Args:
        email: 邮箱地址
    
    Returns:
        bool: 是否为有效邮箱格式
    """
    if not email or not isinstance(email, str):
        return False
    
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return re.match(pattern, email.strip()) is not None


def validate_url(url: str) -> bool:
    """
    验证URL格式
    
    Args:
        url: URL地址
    
    Returns:
        bool: 是否为有效URL格式
    """
    if not url or not isinstance(url, str):
        return False
    
    pattern = r'^https?://[^\s/$.?#].[^\s]*$'
    return re.match(pattern, url.strip()) is not None


def sanitize_string(text: str, max_length: int = 1000) -> str:
    """
    清理和验证字符串输入
    
    Args:
        text: 输入文本
        max_length: 最大长度限制
    
    Returns:
        str: 清理后的文本
    """
    if not text or not isinstance(text, str):
        return ""
    
    # 去除首尾空白
    text = text.strip()
    
    # 限制长度
    if len(text) > max_length:
        text = text[:max_length]
    
    # 移除潜在的危险字符
    # 这里可以根据需要添加更多的清理规则
    text = re.sub(r'[<>"\'\/]', '', text)
    
    return text


def format_datetime(dt: datetime, format_str: str = "%Y-%m-%d %H:%M:%S") -> str:
    """
    格式化日期时间
    
    Args:
        dt: 日期时间对象
        format_str: 格式字符串
    
    Returns:
        str: 格式化后的日期时间字符串
    """
    if not isinstance(dt, datetime):
        return ""
    
    try:
        return dt.strftime(format_str)
    except Exception as e:
        logger.error(f"日期格式化错误: {str(e)}")
        return ""


def parse_datetime(date_str: str, format_str: str = "%Y-%m-%d %H:%M:%S") -> Optional[datetime]:
    """
    解析日期时间字符串
    
    Args:
        date_str: 日期时间字符串
        format_str: 格式字符串
    
    Returns:
        Optional[datetime]: 解析后的日期时间对象，失败返回None
    """
    if not date_str or not isinstance(date_str, str):
        return None
    
    try:
        return datetime.strptime(date_str.strip(), format_str)
    except Exception as e:
        logger.error(f"日期解析错误: {str(e)}")
        return None


def generate_unique_id(prefix: str = "") -> str:
    """
    生成唯一ID
    
    Args:
        prefix: ID前缀
    
    Returns:
        str: 唯一ID
    """
    unique_id = str(uuid.uuid4()).replace('-', '')
    return f"{prefix}{unique_id}" if prefix else unique_id


def generate_hash(text: str, algorithm: str = 'md5') -> str:
    """
    生成文本哈希值
    
    Args:
        text: 输入文本
        algorithm: 哈希算法 ('md5', 'sha1', 'sha256')
    
    Returns:
        str: 哈希值
    """
    if not text or not isinstance(text, str):
        return ""
    
    try:
        if algorithm == 'md5':
            return hashlib.md5(text.encode('utf-8')).hexdigest()
        elif algorithm == 'sha1':
            return hashlib.sha1(text.encode('utf-8')).hexdigest()
        elif algorithm == 'sha256':
            return hashlib.sha256(text.encode('utf-8')).hexdigest()
        else:
            return hashlib.md5(text.encode('utf-8')).hexdigest()
    except Exception as e:
        logger.error(f"哈希生成错误: {str(e)}")
        return ""


def safe_json_loads(json_str: str, default: Any = None) -> Any:
    """
    安全的JSON解析
    
    Args:
        json_str: JSON字符串
        default: 解析失败时的默认值
    
    Returns:
        Any: 解析后的对象或默认值
    """
    if not json_str or not isinstance(json_str, str):
        return default
    
    try:
        return json.loads(json_str)
    except Exception as e:
        logger.error(f"JSON解析错误: {str(e)}")
        return default


def safe_json_dumps(obj: Any, default: str = "") -> str:
    """
    安全的JSON序列化
    
    Args:
        obj: 要序列化的对象
        default: 序列化失败时的默认值
    
    Returns:
        str: JSON字符串或默认值
    """
    try:
        return json.dumps(obj, ensure_ascii=False, separators=(',', ':'))
    except Exception as e:
        logger.error(f"JSON序列化错误: {str(e)}")
        return default


def paginate_list(items: List[Any], page: int = 1, per_page: int = 10) -> Dict[str, Any]:
    """
    对列表进行分页
    
    Args:
        items: 要分页的列表
        page: 页码（从1开始）
        per_page: 每页数量
    
    Returns:
        Dict[str, Any]: 分页结果
    """
    if not items or not isinstance(items, list):
        return {
            'items': [],
            'total': 0,
            'page': page,
            'per_page': per_page,
            'pages': 0,
            'has_prev': False,
            'has_next': False
        }
    
    total = len(items)
    pages = (total + per_page - 1) // per_page  # 向上取整
    
    # 确保页码有效
    if page < 1:
        page = 1
    elif page > pages and pages > 0:
        page = pages
    
    # 计算起始和结束索引
    start = (page - 1) * per_page
    end = start + per_page
    
    return {
        'items': items[start:end],
        'total': total,
        'page': page,
        'per_page': per_page,
        'pages': pages,
        'has_prev': page > 1,
        'has_next': page < pages
    }


def extract_keywords(text: str, max_keywords: int = 10) -> List[str]:
    """
    从文本中提取关键词
    
    Args:
        text: 输入文本
        max_keywords: 最大关键词数量
    
    Returns:
        List[str]: 关键词列表
    """
    if not text or not isinstance(text, str):
        return []
    
    # 简单的关键词提取逻辑
    # 这里可以集成更复杂的NLP库如jieba等
    
    # 移除标点符号和特殊字符
    text = re.sub(r'[^\w\s]', ' ', text)
    
    # 分词并过滤
    words = text.split()
    keywords = []
    
    for word in words:
        word = word.strip().lower()
        if len(word) > 1 and word not in keywords:
            keywords.append(word)
        
        if len(keywords) >= max_keywords:
            break
    
    return keywords


def calculate_similarity(text1: str, text2: str) -> float:
    """
    计算两个文本的相似度（简单实现）
    
    Args:
        text1: 文本1
        text2: 文本2
    
    Returns:
        float: 相似度（0-1之间）
    """
    if not text1 or not text2:
        return 0.0
    
    # 简单的基于词汇重叠的相似度计算
    words1 = set(text1.lower().split())
    words2 = set(text2.lower().split())
    
    if not words1 or not words2:
        return 0.0
    
    intersection = words1.intersection(words2)
    union = words1.union(words2)
    
    return len(intersection) / len(union) if union else 0.0


def format_file_size(size_bytes: int) -> str:
    """
    格式化文件大小
    
    Args:
        size_bytes: 文件大小（字节）
    
    Returns:
        str: 格式化后的文件大小
    """
    if size_bytes == 0:
        return "0 B"
    
    size_names = ["B", "KB", "MB", "GB", "TB"]
    i = 0
    size = float(size_bytes)
    
    while size >= 1024.0 and i < len(size_names) - 1:
        size /= 1024.0
        i += 1
    
    return f"{size:.1f} {size_names[i]}"


def truncate_text(text: str, max_length: int = 100, suffix: str = "...") -> str:
    """
    截断文本
    
    Args:
        text: 输入文本
        max_length: 最大长度
        suffix: 截断后缀
    
    Returns:
        str: 截断后的文本
    """
    if not text or not isinstance(text, str):
        return ""
    
    if len(text) <= max_length:
        return text
    
    return text[:max_length - len(suffix)] + suffix


def is_valid_json(json_str: str) -> bool:
    """
    检查字符串是否为有效的JSON
    
    Args:
        json_str: JSON字符串
    
    Returns:
        bool: 是否为有效JSON
    """
    try:
        json.loads(json_str)
        return True
    except (ValueError, TypeError):
        return False


def merge_dicts(*dicts: Dict[str, Any]) -> Dict[str, Any]:
    """
    合并多个字典
    
    Args:
        *dicts: 要合并的字典
    
    Returns:
        Dict[str, Any]: 合并后的字典
    """
    result = {}
    for d in dicts:
        if isinstance(d, dict):
            result.update(d)
    return result


def get_client_ip(request) -> str:
    """
    获取客户端IP地址
    
    Args:
        request: Flask请求对象
    
    Returns:
        str: 客户端IP地址
    """
    # 检查代理头
    if request.headers.get('X-Forwarded-For'):
        return request.headers.get('X-Forwarded-For').split(',')[0].strip()
    elif request.headers.get('X-Real-IP'):
        return request.headers.get('X-Real-IP')
    else:
        return request.remote_addr or 'unknown'


def log_api_request(request, response_data: Dict[str, Any] = None):
    """
    记录API请求日志
    
    Args:
        request: Flask请求对象
        response_data: 响应数据
    """
    try:
        log_data = {
            'method': request.method,
            'url': request.url,
            'ip': get_client_ip(request),
            'user_agent': request.headers.get('User-Agent', ''),
            'timestamp': datetime.now(timezone.utc).isoformat()
        }
        
        if response_data:
            log_data['response_success'] = response_data.get('success', False)
        
        logger.info(f"API请求: {safe_json_dumps(log_data)}")
        
    except Exception as e:
        print(f"记录API请求日志失败: {str(e)}")